#include "sct/rtspserver/aacsource.h"


#include "InputFile.hh"
#include <GroupsockHelper.hh>

#define DEBUG

static unsigned const samplingFrequencyTable[16] = {
  96000, 88200, 64000, 48000,
  44100, 32000, 24000, 22050,
  16000, 12000, 11025, 8000,
  7350, 0, 0, 0
};

namespace sct
{

CAACSource*
CAACSource::createNew(UsageEnvironment& env, void* audio) {

	uint8_t * buff = NULL;
  do {
	  CStreamSource* enc = (CStreamSource*)audio;

	  int maxlen = 100000;
	  buff = new uint8_t[maxlen];


	  int ret = 0;
	  int64_t pts = 0;
	  int ntrunc = 0;
	  ret = enc->getdata(buff, maxlen, &pts, &ntrunc, 1);

	  if(ret <= 0) break;

	  if(ntrunc > 0)
	  {
		  SCT_LOGD("buffer too small!!! error.");
		  break;
	  }

//    fid = OpenInputFile(env, fileName);
//    if (fid == NULL) break;

    // Now, having opened the input file, read the fixed header of the first frame,
    // to get the audio stream's parameters:
    unsigned char fixedHeader[4]; // it's actually 3.5 bytes long
//    if (fread(fixedHeader, 1, sizeof fixedHeader, fid) < sizeof fixedHeader) break;
    memcpy(fixedHeader, buff, 4);


    // Check the 'syncword':
    if (!(fixedHeader[0] == 0xFF && (fixedHeader[1]&0xF0) == 0xF0)) {
      env.setResultMsg("Bad 'syncword' at start of ADTS file");
      break;
    }

    // Get and check the 'profile':
    u_int8_t profile = (fixedHeader[2]&0xC0)>>6; // 2 bits
    if (profile == 3) {
      env.setResultMsg("Bad (reserved) 'profile': 3 in first frame of ADTS file");
      break;
    }

    // Get and check the 'sampling_frequency_index':
    u_int8_t sampling_frequency_index = (fixedHeader[2]&0x3C)>>2; // 4 bits
    if (samplingFrequencyTable[sampling_frequency_index] == 0) {
      env.setResultMsg("Bad 'sampling_frequency_index' in first frame of ADTS file");
      break;
    }

    // Get and check the 'channel_configuration':
    u_int8_t channel_configuration
      = ((fixedHeader[2]&0x01)<<2)|((fixedHeader[3]&0xC0)>>6); // 3 bits

    // If we get here, the frame header was OK.
    // Reset the fid to the beginning of the file:
#ifndef _WIN32_WCE
//    rewind(fid);
#else
    SeekFile64(fid, SEEK_SET,0);
#endif
#ifdef DEBUG
    fprintf(stderr, "Read first frame: profile %d, "
	    "sampling_frequency_index %d => samplingFrequency %d, "
	    "channel_configuration %d\n",
	    profile,
	    sampling_frequency_index, samplingFrequencyTable[sampling_frequency_index],
	    channel_configuration);
#endif
    SCT_DELETE_ARRAY(buff);
    return new CAACSource(env, enc, profile,
				   sampling_frequency_index, channel_configuration);
  } while (0);

  // An error occurred:
//  CloseInputFile(fid);
  SCT_DELETE_ARRAY(buff);
  return NULL;
}

CAACSource
::CAACSource(UsageEnvironment& env, CStreamSource * audio, u_int8_t profile,
		      u_int8_t samplingFrequencyIndex, u_int8_t channelConfiguration)
  : FramedSource(env), mSource(audio),mStartReadTime(0), mReadTask(NULL){
  fSamplingFrequency = samplingFrequencyTable[samplingFrequencyIndex];
  fNumChannels = channelConfiguration == 0 ? 2 : channelConfiguration;
  fuSecsPerFrame
    = (1024/*samples-per-frame*/*1000000) / fSamplingFrequency/*samples-per-second*/;

  // Construct the 'AudioSpecificConfig', and from it, the corresponding ASCII string:
  unsigned char audioSpecificConfig[2];
  u_int8_t const audioObjectType = profile + 1;
  audioSpecificConfig[0] = (audioObjectType<<3) | (samplingFrequencyIndex>>1);
  audioSpecificConfig[1] = (samplingFrequencyIndex<<7) | (channelConfiguration<<3);
  sprintf(fConfigStr, "%02X%02x", audioSpecificConfig[0], audioSpecificConfig[1]);
}

CAACSource::~CAACSource() {
//  CloseInputFile(fFid);
	if(mReadTask)
	{
		envir().taskScheduler().unscheduleDelayedTask(mReadTask);
	}
}

// Note: We should change the following to use asynchronous file reading, #####
// as we now do with ByteStreamFileSource. #####
void CAACSource::tryToGetNextFrame(void* p) {
	CAACSource* self = (CAACSource*)p;
	self->mReadTask = NULL;

	if( !self->isCurrentlyAwaitingData() )
	{
		return;
	}

	int ret = 0;
	int64_t pts = 0;
	int ntrunc = 0;

	ret = self->mSource->getdata(self->fTo, self->fMaxSize, &pts, &ntrunc);
	if(ret <= 0)
	{
		if(currentTime() - self->mStartReadTime > 3)
		{
			self->handleClosure();
		}
		else
		{
			self->mReadTask = self->envir().taskScheduler().scheduleDelayedTask(50000,
						tryToGetNextFrame, self);
		}
		return;
	}

	unsigned char headers[7];
	memcpy(headers, self->fTo, sizeof(headers));
	Boolean protection_absent = headers[1]&0x01;

	int offset = 7;
	if(!protection_absent)
	{
		offset += 2;
	}

	ret -= offset;
	memmove(self->fTo, self->fTo+offset, ret);

//	SCT_LOG("%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
//			headers[0],
//			headers[1],
//			headers[2],
//			headers[3],
//			headers[4],
//			headers[5],
//			headers[6]
//			);

	self->fFrameSize = ret;
	self->fNumTruncatedBytes = ntrunc;

	self->fPresentationTime.tv_sec = pts / 1000000;
	self->fPresentationTime.tv_usec = pts % 1000000;

	self->fDurationInMicroseconds = 0;

	self->nextTask() = self->envir().taskScheduler().scheduleDelayedTask(0,
			(TaskFunc*)FramedSource::afterGetting, self);
}

void CAACSource::doGetNextFrame()
{
	if(NULL == mReadTask)
	{
		mStartReadTime = currentTime();
		mReadTask = envir().taskScheduler().scheduleDelayedTask(0,
			tryToGetNextFrame, this);
	}
	else
	{
		SCT_LOGD();
	}
}

void CAACSource::doStopGettingFrames()
{
	if(mReadTask)
	{
		envir().taskScheduler().unscheduleDelayedTask(mReadTask);
	}
}


}
